package com.xuhuan.demo.file;

import java.net.HttpURLConnection;
import java.net.URL;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 徐欢
 * @date: 2021/9/17 10:26
 * @description: 文件工具类
 */
@Slf4j
public class FileUtil {

    /**
     * 将set中的内容写入目标文件
     *
     * @param codeSet
     * @param targetFile
     */
    public static void writeSetToText(Set<String> codeSet, File targetFile) {
        if (CollectionUtils.isNotEmpty(codeSet)) {
            BufferedWriter bufferedWriter = null;
            FileWriter fileWriter = null;
            try {
                fileWriter = new FileWriter(targetFile);
                bufferedWriter = new BufferedWriter(fileWriter);
                for (String code : codeSet) {
                    bufferedWriter.write(code);
                    bufferedWriter.newLine();
                    bufferedWriter.flush();
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fileWriter != null) {
                    try {
                        fileWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (bufferedWriter != null) {
                    try {
                        bufferedWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }
        }
    }

    /**
     * 读取文本文件到set集合
     *
     * @param file
     * @return
     */
    public static Set<String> readTextToSet(File file) {
        Set<String> textSet = new LinkedHashSet<>();

        long startTime = System.currentTimeMillis();
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;

        try {
            fileReader = new FileReader(file);

            bufferedReader = new BufferedReader(fileReader);

            String lineRead;
            //读取一行,null代表已经读到流末尾
            while ((lineRead = bufferedReader.readLine()) != null) {
                if (!textSet.add(lineRead)) {
                    log.info("重复数据[{}]", lineRead);
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        long endTime = System.currentTimeMillis();
        log.info("花费时间[{}]毫秒", (endTime - startTime));

        return textSet;
    }

    /**
     * 获取文件类型
     *
     * @param fileFullName
     * @return
     */
    public static String getFileType(String fileFullName) {
        if (StringUtils.isNotBlank(fileFullName)) {
            return fileFullName.substring(fileFullName.lastIndexOf(".") + 1, fileFullName.length());
        }
        return "";
    }

    /**
     * 打印文件树
     *
     * @param dirPath        目录
     * @param ignoreFileType 忽略的文件类型
     */
    public static void printFileTree(String dirPath, String[] ignoreFileType) {
        log.info("开始打印目录【{}】下的文件树");
        File parentDir = new File(dirPath);
        if (!parentDir.exists()) {
            throw new RuntimeException("要打印的目录不存在");
        }
        getFileTree(parentDir, 0, ignoreFileType);
        log.info("结束打印");
    }

    private static void getFileTree(File file, int level, String[] ignoreFileType) {
        String fileName = file.getName();
        if (file.isDirectory()) {
            log.info("{}{}{}", getLevelStr(level), "(D)", fileName);
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                int tempLevel = level + 1;
                for (File f : files) {
                    getFileTree(f, tempLevel, ignoreFileType);
                }
            }
        } else {
            boolean contains = ArrayUtils.contains(ignoreFileType, FileUtil.getFileType(fileName));
            if (!contains) {
                log.info("{}{}{}", getLevelStr(level), "(F)", fileName);
            }

        }
    }

    /**
     * 组装不同级别的缩进符号
     *
     * @param level
     * @return
     */
    private static String getLevelStr(int level) {
        StringBuilder levelStr = new StringBuilder("|");
        for (int i = 0; i <= level; i++) {
            levelStr.append("--");
        }
        return levelStr.toString();
    }


    /**
     * 获取目录下所有的文件
     *
     * @param dir
     * @param resultSet
     * @return
     */
    public static void getDirFileSet(File dir, Set<String> resultSet) {
        if (dir.isDirectory()) {
            File[] files = dir.listFiles();
            for (File file : files) {
                getDirFileSet(file, resultSet);
            }
        } else if (dir.isFile()) {
            resultSet.add(dir.getName());
        }
    }

    /**
     * 合并目录下的txt文件中的内容到指定的文件
     *
     * @param codeTxtDir         code.txt所在目录
     * @param ignoreCodeTxtFiles codeTxtDir目录中希望忽略的code.txt文件名称
     * @param resultFile         合并后的文件
     */
    public static void mergeCodeTxt(File codeTxtDir, String[] ignoreCodeTxtFiles, File resultFile) {
        //1.得到要合并的txt集合
        List<String> ignoreCodeTxtFileList = null;
        if (ignoreCodeTxtFiles != null && ignoreCodeTxtFiles.length > 0) {
            ignoreCodeTxtFileList = Arrays.asList(ignoreCodeTxtFiles);
        }
        List<String> finalIgnoreCodeTxtFileList = ignoreCodeTxtFileList;
        List<File> codeTxtList = Arrays.stream(codeTxtDir.listFiles())
            .filter(f -> "txt".equals(getFileType(f.getPath())))
            .filter(f -> {
                if (CollectionUtils.isNotEmpty(finalIgnoreCodeTxtFileList)) {
                    return !finalIgnoreCodeTxtFileList.contains(f.getName());
                }
                return true;
            }).collect(Collectors.toList());

        //2.读取每个文件到set集合中
        Set<String> resultCodeSet = new HashSet<>();
        codeTxtList.stream()
            .forEach(f -> {
                resultCodeSet.addAll(readTextToSet(f));
            });

        //3.写入结果文件
        writeSetToText(resultCodeSet, resultFile);

    }

    /**
     * 汇总要部署的多个发布包中的部署说明文件到指定目录
     *
     * @param docDir               多个部署包的上级目录
     * @param ignoreChildrenDocDir 忽略的部署包名称
     * @param resultDoc            汇总后的存放地址
     * @param num                  文档编号从几号开始
     */
    public static void mergeDeployDoc(File docDir, String[] ignoreChildrenDocDir, File resultDoc,
        int num) {
        //1. 得到要汇总的所有发布包
        List<String> ignoreChildrenDocDirList = null;
        if (ignoreChildrenDocDir != null && ignoreChildrenDocDir.length > 0) {
            ignoreChildrenDocDirList = Arrays.asList(ignoreChildrenDocDir);
        }
        List<String> finalIgnoreChildrenDocDirList = ignoreChildrenDocDirList;
        List<Map> bsCollectList = Arrays.stream(docDir.listFiles())
            .filter(d -> {
                //过滤忽略的目录
                if (CollectionUtils.isNotEmpty(finalIgnoreChildrenDocDirList)) {
                    return !finalIgnoreChildrenDocDirList.contains(d.getName());
                }
                return true;
            })
            .sorted()
            .map(d -> {
                Map resultMap = new HashMap(2);
                //获取部署文档
                List<File> bsDocs = Arrays.stream(d.listFiles())
                    .filter(f -> {
                        String fileType = getFileType(f.getName());
                        if ("doc".equals(fileType) || "docx".equals(fileType)) {
                            if (f.getName().startsWith("部署")) {
                                return true;
                            }
                        }
                        return false;
                    })
                    .collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(bsDocs)) {
                    File doc = bsDocs.get(0);
                    resultMap.put("fileType", getFileType(doc.getName()));
                    resultMap.put("fileName", doc.getName());
                    resultMap.put("filePath", doc.getPath());
                    //获取上级名称
                    String parentDocName = doc.getParent()
                        .substring(doc.getParent().lastIndexOf("\\") + 1);
                    resultMap.put("parentDocName", parentDocName);
                    return resultMap;
                }
                return new HashMap(1);
            })
            .filter(m -> m != null && m.size() > 0)
            .collect(Collectors.toList());

        //2. 复制到结果目录，并且命名
        String savePathPrefix = resultDoc.getPath() + File.separator;
        for (Map docFileMap : bsCollectList) {
            String fileType = (String) docFileMap.get("fileType");
            String filePath = (String) docFileMap.get("filePath");
            String parentDocName = (String) docFileMap.get("parentDocName");
            String savePath = savePathPrefix + num + "_" + parentDocName + "." + fileType;
            System.out.println(savePath);
            IOUtil.copyFileByteArray(filePath, savePath);
            num++;
        }
    }

    /**
     * 从url中获取文件byte数据
     * @param fileUrl
     * @return
     * @throws Exception
     */
    public static byte[] getUrlFileData(String fileUrl) throws Exception {
        URL url = new URL(fileUrl);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        httpConn.connect();
        InputStream cin = httpConn.getInputStream();
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = cin.read(buffer)) != -1) {
            outStream.write(buffer, 0, len);
        }
        cin.close();
        byte[] fileData = outStream.toByteArray();
        outStream.close();
        return fileData;
    }

    /**
     * 从url中获取文件，并写入本地文件
     * @param fileUrl
     * @param fileDes
     * @throws Exception
     */
    public static void saveUrlFile(String fileUrl, String fileDes) throws Exception {
        File toFile = new File(fileDes);
        if (toFile.exists()) {
            // throw new Exception("file exist");
            return;
        }
        toFile.createNewFile();
        FileOutputStream outImgStream = new FileOutputStream(toFile);
        outImgStream.write(getUrlFileData(fileUrl));
        outImgStream.close();
    }

    public static void main(String[] args) throws Exception {
        String url="http://192.168.159.102/ftp/homeManage/20221112/e7e3a0c75a954ca9802a37f23d1f16f1.png";
        String saveFilePath="C:\\Users\\Administrator\\Desktop\\1.png";
        saveUrlFile(url,saveFilePath);
    }
}
